package org.tau.workshop2011.parsing.AST

import org.tau.workshop2011.expressions.Type
import java.lang.AssertionError

object AtomicWidget {
  val propTypes = Map(
    ("text", Type.tString),
    ("image", Type.tString),
    ("checked", Type.tBoolean),
    ("value", Type.tInt),
    ("enabled", Type.tBoolean),
    ("fgcolor", Type.tColor),
    ("bgcolor", Type.tColor),
    ("font", Type.tFont),
    ("halign", Type.tHAlign),
    ("valign", Type.tVAlign),
    ("minvalue", Type.tInt),
    ("maxvalue", Type.tInt)
  )

  val globalPropTypes = Map(
    ("width", Type.tInt),
    ("height", Type.tInt)
  )

  val typeSpecificProps = Map(
    ("label", List("text", "enabled", "fgcolor", "bgcolor", "font", "halign", "valign")),
    ("textbox", List("text", "enabled", "fgcolor", "bgcolor", "font")),
    ("button", List("text", "image", "checked", "enabled", "fgcolor", "bgcolor", "font", "halign", "valign")),
    ("checkbox", List("checked", "enabled", "fgcolor", "bgcolor")),
    ("radio", List("checked", "enabled", "fgcolor", "bgcolor")),
    ("image", List("image", "enabled", "bgcolor")),
    ("combobox", List("text", "value", "enabled", "fgcolor", "bgcolor", "font")),
    ("slider", List("value", "enabled", "fgcolor", "bgcolor", "minvalue", "maxvalue")),
    ("", List("fgcolor", "bgcolor"))
  )

  def widgetHasNativeProp(kind: String, propName: String): Boolean = {
    typeSpecificProps.get(kind) match {
      case None => false /* Empty widget or some other custom widget */
      case Some(props) => props contains propName
    }
  }

  def getPropType(kind: String, propName: String): Type = {
    assume(widgetHasNativeProp(kind, propName))
    propTypes.get(propName) match {
      case Some(pType) => pType
      case _ => throw new AssertionError ()
    }
  }

  def isGlobalProp (propName:String) : Boolean = {
    globalPropTypes.get(propName) != None
  }

  def globalPropType (propName:String) : Type = {
    assume (isGlobalProp(propName))
    globalPropTypes.get(propName) match {
      case Some (pType) => pType
      case _ => throw new AssertionError ()
    }
  }

  def isNativeWidget (kind:String) : Boolean = {
    typeSpecificProps.get(kind) match {
      case None => false /* Empty widget or some other custom widget */
      case _ => true
    }
  }

}

case class AtomicWidget(kind: String, attributes: List[Attribute], width: Option[DirectExpr], height: Option[DirectExpr]) extends Widget(kind, width, height) {

  def autoResolveAttributes() {
    for (attr <- attributes) {
      attr match {
        case attr:ExpressionAttribute => {
          if (AtomicWidget.widgetHasNativeProp(kind, attr.getName))
            attr.resolveTypeTo(AtomicWidget.getPropType(kind, attr.getName))
          else
            attr.autoResolveType
          }
        case attr:InitialAttribute => {
          if (attr.value == None && AtomicWidget.widgetHasNativeProp(kind, attr.getName))
            throw new Exception ("A native property (" + attr.getName + " of the " +
              "widget " + kind + ") can not be declared as a direct input of " +
              "the program!")
          else
            attr.autoResolveType
        }
      }
    }
  }

  override def accept(visitor: ASTVisitor): Any = visitor.visit(this)

  override def toString = {
    "(" +
      kind +
      ":" +
      (width match { case None => "?"; case Some(w) => "(" + w + ")" }) +
      "x" +
      (height match { case None => "?"; case Some(w) => "(" + w + ")" }) +
    ")" +
      attributes.mkString("[", ", ", "]")
  }
}